
#include "btl_sdk_mass_production_test_protocol.h"
#include "btl_bep.h"
#include "btl_special_api.h"
#include "btl_external_template_storage.h"

#include "fp_led.h"

/* version */
static const unsigned char g_software_version[40] __attribute__((aligned(4))) = "QSX-V1.0.0";

#define XU_ABS(a) (((a) > 0) ? (a) : -(a))

unsigned char Response_buffer[100];
unsigned char Usart_rx_buffer[100];

unsigned char g_cmd_test_image = 0;

void uart0_sendbyte(unsigned char c);


void power_set_soft_poweroff(void);
void spple_set_soft_poweroff(void);
void charge_close(void);

void do_poweroff(void)
{
    power_set_soft_poweroff();
    
    // charge_close();
    // spple_set_soft_poweroff();
}

//////////////////////需要客户实现的接口(Need to be realized by customers)///////////////////////
void btl_customer_usart_send_byte(uint8_t byte)
{
    uart0_sendbyte(byte);
}

void btl_customer_get_software_version(uint8_t** software_version, int* size)
{
    *software_version = &g_software_version;
    *size = strlen(g_software_version) + 1;
}

void btl_customer_get_module_uid(uint8_t** uuid, int* size)
{
    *uuid = get_norflash_uuid();
    *size = 16;
}

void btl_customer_set_led(uint8_t red_on, uint8_t green_on, uint8_t blue_on)
{
    if (red_on || green_on || blue_on) {
        if (red_on) {
            fp_led_ctrl(FP_LED1, LED_ON);
            fp_led_ctrl(FP_LED2, LED_OFF);
            fp_led_ctrl(FP_LED3, LED_OFF);
        }
        if (green_on) {
            fp_led_ctrl(FP_LED1, LED_OFF);
            fp_led_ctrl(FP_LED2, LED_OFF);
            fp_led_ctrl(FP_LED3, LED_ON);
        }
        if (blue_on) {
            fp_led_ctrl(FP_LED1, LED_OFF);
            fp_led_ctrl(FP_LED2, LED_ON);
            fp_led_ctrl(FP_LED3, LED_OFF);
            // fp_moto(MOTO_FORWARD);
        }
    } else {
        fp_led_ctrl(FP_LED1, LED_OFF);
        fp_led_ctrl(FP_LED2, LED_OFF);
        fp_led_ctrl(FP_LED3, LED_OFF);
        // fp_moto(MOTO_STOP);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////

void BTL_UsartSendData(const unsigned char cmd, const unsigned char* buffer, const unsigned int num)
{
    unsigned int check_sum = 0;
    unsigned int i;

    btl_customer_usart_send_byte(BTL_HEAD1);
    check_sum += BTL_HEAD1;
    btl_customer_usart_send_byte(BTL_HEAD2);
    check_sum += BTL_HEAD2;
    btl_customer_usart_send_byte(cmd);
    check_sum += cmd;

    btl_customer_usart_send_byte((num) >> 8);
    check_sum += ((num) >> 8);
    btl_customer_usart_send_byte((num) & 0xff);
    check_sum += ((num) & 0xff);
    for (i = 0; i < num; i++) {
        btl_customer_usart_send_byte(buffer[i]);
        check_sum += buffer[i];
    }
    btl_customer_usart_send_byte(check_sum >> 8);
    btl_customer_usart_send_byte(check_sum & 0xff);
}

void BTL_CommandAnalysis(unsigned char* data_buffer)
{
    uint8_t i;
    uint8_t* buffer_p = NULL;
    int buffer_size;
    uint8_t cmd = data_buffer[2];
    uint32_t Sensor_ID = 0x83112;

    memset(Response_buffer, 0, sizeof(Response_buffer));

    switch (cmd) {
        case 0xe6: /* low power mode */
            if (BTL_RC_OK == btl_set_work_mode(BTL_IDLE_MODE)) {
                Response_buffer[0] = 0;
            } else {
                Response_buffer[0] = 1;
            }
            BTL_UsartSendData(cmd, Response_buffer, 1);

            do_poweroff();

            break;
        case 0x80:  // set work mode
            switch (data_buffer[5]) {
                case 0x10:  // idle mode
                    if (BTL_RC_OK == btl_set_work_mode(BTL_IDLE_MODE)) {
                        Response_buffer[0] = 0;
                    } else {
                        Response_buffer[0] = 1;
                    }
                    BTL_UsartSendData(cmd, Response_buffer, 1);

                    // do_poweroff();
                    break;
                case 0x50:  // capture mode
                    if (BTL_RC_OK == btl_set_work_mode(BTL_GET_IMAGE_MODE)) {
                        Response_buffer[0] = 0;
                    } else {
                        Response_buffer[0] = 1;
                    }
                    BTL_UsartSendData(cmd, Response_buffer, 1);
                    break;
                case 0x60:  // finger detect mode
                    if (BTL_RC_OK == btl_set_work_mode(BTL_FINGER_DETECT_MODE)) {
                        Response_buffer[0] = 0;
                    } else {
                        Response_buffer[0] = 1;
                    }
                    BTL_UsartSendData(cmd, Response_buffer, 1);
                    break;
            }
            break;

        case 0x83:  // force to capture image
            g_cmd_test_image = cmd;
            break;

        case 0x86:  // get param
            Response_buffer[0] = data_buffer[5];
            switch (data_buffer[5]) {
                case 0x01: {  // get software version
                    btl_customer_get_software_version(&buffer_p, &buffer_size);
                    memcpy(&Response_buffer[1], buffer_p, buffer_size);
                    BTL_UsartSendData(cmd, Response_buffer, buffer_size + 1);  //
                } break;
                case 0x0c:  // get module UID
                    btl_customer_get_module_uid(&buffer_p, &buffer_size);
                    memcpy(&Response_buffer[1], buffer_p, buffer_size);
                    BTL_UsartSendData(cmd, Response_buffer, buffer_size + 1);
                    break;
                case 0x0D:  // read sensor register
                    Response_buffer[1] = data_buffer[6];
                    btl_read_register(data_buffer[6], &Response_buffer[2]);
                    BTL_UsartSendData(cmd, Response_buffer, 3);
                    break;
                case 0x0f:  // get sensor id
                    Sensor_ID = btl_get_sensor_id();
                    Response_buffer[1] = 0;
                    Response_buffer[2] = (uint8_t)(Sensor_ID >> 16);
                    Response_buffer[3] = (uint8_t)(Sensor_ID >> 8);
                    Response_buffer[4] = (uint8_t)Sensor_ID;
                    BTL_UsartSendData(cmd, Response_buffer, 5);
                    break;
            }
            break;

        case 0x87:  // set param
            switch (data_buffer[5]) {
                case 0x08:  // write sensor register
                    if (BTL_RC_OK == btl_write_register(data_buffer[6], data_buffer[7])) {
                        Response_buffer[1] = 0;
                    } else {
                        Response_buffer[1] = 1;
                    }
                    BTL_UsartSendData(cmd, Response_buffer, 2);  //
                    break;
            }
            break;

        case 0xe0:  // check image quality
            g_cmd_test_image = cmd;
            break;

        case 0xe1:  // check sensor connection
            btl_set_work_mode(BTL_IDLE_MODE);
            Response_buffer[0] = 0;
            switch (blt_sensor_connected_status_test()) {
                case BTL_SCS_OK:
                    Response_buffer[0] = 0x00;
                    break;
                case BTL_SCS_SPI_ERR:
                    Response_buffer[0] |= 0x02;  // SPI abnormal
                    break;
                case BTL_SCS_ID_ERR:
                    Response_buffer[0] |= 0x04;  // sensor ID abnormal
                    break;
                case BTL_SCS_RST_ERR:
                    Response_buffer[0] |= 0x01;  // rst pin abnormal
                    break;
                case BTL_SCS_INT_ERR:
                    Response_buffer[0] |= 0x08;  // int pin abnormal
                    break;
                default:
                    Response_buffer[0] = 0x00;
                    break;
            }
            BTL_UsartSendData(cmd, Response_buffer, 1);
            break;
        case 0xe3:  // use to measure the current of capture
            Response_buffer[0] = 0;
            BTL_UsartSendData(cmd, Response_buffer, 1);
            btl_set_work_mode(BTL_IDLE_MODE);
            btl_force_image_without_print(data_buffer[5], 100);
            break;
        case 0xe4:  // sensitivity test
            btl_force_image_without_agc();
            btl_get_image_center_value(&Response_buffer[0]);
            BTL_UsartSendData(cmd, Response_buffer, 1);
            break;

        case 0x8B:  // LED control
            if (data_buffer[5] == 0) {
                btl_customer_set_led(0, 0, 0);  // off
            } else {
                if (data_buffer[6] == 0) {  // RED
                    btl_customer_set_led(1, 0, 0);
                } else if (data_buffer[6] == 1) {  // GREEN
                    btl_customer_set_led(0, 1, 0);
                } else if (data_buffer[6] == 2) {  // BLUE
                    btl_customer_set_led(0, 0, 1);
                }
            }

            Response_buffer[0] = 0;
            BTL_UsartSendData(cmd, Response_buffer, 1);
            break;
        case 0x8C:  // upload image data
            Response_buffer[0] = 0;
            BTL_UsartSendData(cmd, Response_buffer, 1);
            g_cmd_test_image = cmd;
            break;
    }
}

uint16_t cheksum_add(uint8_t* t, uint16_t len)
{
    uint16_t i = 0;
    uint16_t result = 0;
    for (i = 0; i < len; i++) {
        result += *t++;
    }
    return result;
}

int btl_cmd_rx(unsigned char data)
{
    int ret = 0;
    static uint16_t btl_test_step = 0;
    static uint16_t btl_current_length = 0;
    static uint16_t btl_target_length = 0;

    switch (btl_test_step) {
        case 0:
            btl_current_length = 0;
            if (data == BTL_HEAD1) {
                btl_test_step = 1;
                Usart_rx_buffer[btl_current_length++] = data;
            } else {
                btl_test_step = 0;
                ret = -1;
            }
            break;

        case 1:
            if (data == BTL_HEAD2) {
                btl_test_step = 2;
                Usart_rx_buffer[btl_current_length++] = data;
            } else {
                btl_test_step = 0;
                ret = -1;
            }
            break;

        case 2:
            Usart_rx_buffer[btl_current_length++] = data;

            if (5 == btl_current_length)
                btl_target_length = (Usart_rx_buffer[3] << 8) + Usart_rx_buffer[4];

            if (btl_current_length == btl_target_length + 7) {
                uint16_t checksum = cheksum_add(Usart_rx_buffer, btl_target_length + 5);
                uint16_t expected = ((Usart_rx_buffer[btl_target_length + 5] << 8) +
                                     Usart_rx_buffer[btl_target_length + 6]);
                if (checksum == expected) {
                    BTL_CommandAnalysis(Usart_rx_buffer);
                    ret = BTL_TEST_PROTOCOL;
                } else {
                    ret = -1;
                }

                btl_current_length = 0;
                btl_target_length = 0;
                btl_test_step = 0;
            }
            break;
    }

    return ret;
}

void btl_cmd_process(void)
{
    int nBadPixelsNum = 0;

    if (0xe0 == g_cmd_test_image) {
        if (BTL_RC_OK == btl_capture_image(1)) {
            Response_buffer[0] = 0;

            Response_buffer[1] = btl_get_image_quality().nQuality;
            Response_buffer[2] = btl_get_image_quality().nArea;
            Response_buffer[3] = btl_get_image_quality().nConditon;

            btl_computeSNR(&Response_buffer[4], &Response_buffer[5], &Response_buffer[6]);
#define BADLINETHRESHOLD      50
#define BADPIXELSNUMTHRESHOLD 0
            btl_get_badpixels_count(BADLINETHRESHOLD, BADPIXELSNUMTHRESHOLD, &nBadPixelsNum);

            Response_buffer[7] = (uint8_t)((nBadPixelsNum >> 8) & 0x00ff);
            Response_buffer[8] = (uint8_t)(nBadPixelsNum & 0x00ff);

            BTL_UsartSendData(g_cmd_test_image, Response_buffer, 9);
            g_cmd_test_image = 0;
        }
    } else if (0x83 == g_cmd_test_image) {
        if (BTL_RC_OK == btl_capture_image(1)) {
            BTL_UsartSendData(g_cmd_test_image, btl_get_image_data(),
                              btl_get_image_width() * btl_get_image_height());
            g_cmd_test_image = 0;
        }
    } else if (0x8c == g_cmd_test_image) {
        BTL_UsartSendData(0x83, btl_get_image_data(),
                          btl_get_image_width() * btl_get_image_height());
        g_cmd_test_image = 0;
    }
}


